package com.nmgs.util;

import com.nmgs.common.MessageEnum;
import com.nmgs.common.PPException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;

/**
 * @author: shuguang
 * @date: 2022年10月13日 10:52
 * @description: 文件工具类
 */
@Slf4j
public class FileUtil {

    /**
     * 复制文件到新的文件路径
     *
     * @param oldFilePath 源文件路径
     * @param newFilePath 复制文件路径
     * @author shuguang
     * @date 2023-01-12 8:33
     */
    public static void copyFile(String oldFilePath, String newFilePath) {
        //拷贝备份文件到备份目录
        try {
            FileUtils.copyFile(new File(oldFilePath), new File(newFilePath));
        } catch (IOException e) {
            e.printStackTrace();
            log.error("拷贝备份文件{},到{}失败:{}", oldFilePath, newFilePath, e.getMessage(), e);
        }
    }


    public static void copyFile(String oldPath, String newPath, String newFileName) {
        //拷贝备份文件到备份目录
        try {
            //需要复制到的路径，以及图片的新命名+格式
            File result = new File(newPath + newFileName);
            //判断该文件夹是否存在,不存在则新增
            if (!result.getParentFile().exists()) {
                result.getParentFile().mkdirs();
            }
            if (!new File(newPath + newFileName).exists()) {
                //需要复制的原图的路径+图片名+ .png(这是该图片的格式)
                FileInputStream input = new FileInputStream(oldPath);
                FileOutputStream out = new FileOutputStream(result);
                //一个容量，相当于打水的桶，可以自定义大小
                byte[] buffer = new byte[1024];
                int hasRead = 0;
                while ((hasRead = input.read(buffer)) > 0) {
                    //0：表示每次从0开始
                    out.write(buffer, 0, hasRead);
                }
                input.close();
                out.close();
            }
        } catch (IOException e) {
            log.error("拷贝备份文件{},到{}失败:{}", oldPath, newPath, e.getMessage(), e);
        }
    }

    /**
     * 根据路径创建文件夹
     *
     * @param path 路径
     * @author shuguang
     * @date 2022-10-16 13:07
     */
    public static void fileCreat(String path) {
        File file = new File(path);
        if (!file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * 使用walkFileTree方法遍历整个文件目录树，使用FileVisitor处理遍历出来的每一项文件或文件夹
     * FileVisitor的visitFile方法用来处理遍历结果中的“文件”，所以我们可以在这个方法里面删除文件
     *
     * @param filePath
     * @throws IOException
     */
    public static void deleteFileByWalkFileTree(String filePath) {
        Path path = Paths.get(filePath);
        try {
            Files.walkFileTree(path,
                    new SimpleFileVisitor<Path>() {
                        // 先去遍历删除文件
                        @Override
                        public FileVisitResult visitFile(Path file,
                                                         BasicFileAttributes attrs) throws IOException {
                            Files.delete(file);
                            System.out.printf("文件被删除 : %s%n", file);
                            return FileVisitResult.CONTINUE;
                        }

                        // 再去遍历删除目录
                        @Override
                        public FileVisitResult postVisitDirectory(Path dir,
                                                                  IOException exc) throws IOException {
                            Files.delete(dir);
                            System.out.printf("文件夹被删除: %s%n", dir);
                            return FileVisitResult.CONTINUE;
                        }

                    }
            );
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 删除文件夹（强制删除）
     *
     * @param file
     */
    public static void deleteAllFilesOfDir(File file) {
        if (null != file) {
            if (!file.exists())
                return;
            if (file.isFile()) {
                boolean result = file.delete();
                int tryCount = 0;
                while (!result && tryCount++ < 10) {
                    System.gc(); // 回收资源
                    result = file.delete();
                }
            }
            File[] files = file.listFiles();
            if (null != files) {
                for (int i = 0; i < files.length; i++) {
                    deleteAllFilesOfDir(files[i]);
                }
            }
            file.delete();
        }
    }


    /**
     * 删除文件
     *
     * @param pathname
     * @return
     */
    public static boolean deleteFile(String pathname) {
        boolean result = false;
        File file = new File(pathname);
        if (file.exists()) {
            file.delete();
            result = true;
            System.out.println("文件已经被成功删除");
        }
        return result;
    }

    /**
     * 删除指定文件夹下包含文件名的文件
     *
     * @param folderPath       指定文件夹
     * @param fileNameToDelete 要删除的文件名
     * @author shuguang
     * @date 2023-11-14 21:10
     */
    public static void delContainsFileName(String folderPath, String fileNameToDelete) {
        File folder = new File(folderPath);
        if (folder.isDirectory()) {
            File[] files = folder.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.getName().contains(fileNameToDelete)) {
                        boolean isDeleted = file.delete();
                        if (isDeleted) {
                            log.info("已删除文件：{}", file.getAbsolutePath());
                        } else {
                            log.info("无法删除文件：{}", file.getAbsolutePath());
                        }
                    }
                }
            }
        } else {
            log.info("给定的路径不是一个文件夹");
        }
    }

    /**
     * 删除
     *
     * @param file
     */
    public static boolean delete(File file) {
        boolean result = file.delete();
        if (result) {
            log.info("删除: {} 成功", file.getAbsolutePath());
        } else {
            log.warn("删除: {} 失败", file.getAbsolutePath());
        }

        return result;
    }

    public static void fileInput(HttpServletResponse response, String filename, File filePath) {
        if (filePath.exists()) {
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                response.setContentType("application/octet-stream;charset=utf-8");
                // 在controller层中的二进制流文件下载方法下配置放行属性：
                response.setHeader("Access-Control-Expose-Headers", "content-disposition");
                response.setHeader("content-disposition", "attachment;filename=" + java.net.URLEncoder.encode(filename, "UTF-8"));
                byte[] buffer = new byte[4096];
                fis = new FileInputStream(filePath);
                //增加文件的大小
                response.setContentLengthLong(fis.available());
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new PPException(MessageEnum.下载文件失败.getCode(), MessageEnum.下载文件失败.getMessage());
            } finally {
                if (bis != null) {
                    try {
                        bis.close();
                        // 删除临时文件
                        //filePath.delete();
                    } catch (IOException e) {
                        log.info(e.getMessage(), e);
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        log.error(e.getMessage(), e);
                    }
                }
            }
        }
    }

    /**
     * 判断文件是否存在
     */
    public static boolean fileExists(String plainFilePath) {
        File file = new File(plainFilePath);
        return file.exists();
    }
}
